//#include "myLog.hpp"
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <unordered_map>
#include <queue>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>



#include "myLog.hpp"


#define SIZE 1024 


class UdpServer
{
private:

    uint16_t _port ;  // 端口号  //端口号本质就是16位无符号整数
    std::string _ip ; // ip地址
    int _sock ;
    std::unordered_map<std::string, sockaddr_in> _users ; 
    std::queue<std::string> _messageQueue ;

public:

    //uint16_t : 无符号16位整数
    UdpServer(uint16_t port, std::string ip = "" )
    :_port(port)
    ,_ip(ip)
    {

    }


    bool initServer()
    {
        //创建套接字  // AF_INET: IPv4协议 
        //SOCK_DGRAM：数据报套接字，也称为无连接的套接字,使用UDP协议实现。
        _sock = socket(AF_INET, SOCK_DGRAM , 0);  
        if(_sock < 0)
        {
            logMessage(FATAL,"%s:%d",errno,strerror(errno));
            exit(2);
        }
        
        //将用户设置的套接字在内核中和当前进程强关联
        sockaddr_in local ;  
        // 系统用于表示套接字信息的结构体
        bzero( &local , sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port); // 字节序转换函数 h to n s ；

        // string::_ip 转为 字符串 再转为4字节整数ip地址 ;
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if(bind(_sock, (sockaddr*)&local, sizeof local )< 0)
        {
            logMessage(FATAL, "%d:%s" , errno , strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "init udo server done —— %s", strerror(errno));
        return true ; 
    }


    void Start()
    {
        //服务器不会退出 
        char buffer[SIZE] ; 
        for(; ;)
        { 
            // 接受信息

            // peer, 输出型参数 用于储存发送方信息
            sockaddr_in peer ; 
            bzero(&peer , sizeof peer) ; 
            socklen_t len = sizeof(peer);
            char result[256];  //存储输入内容 ？？？？
            char key[64]; // 存储ip 和 端口号
            std::string cmd_echo ; 
            ssize_t s = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&peer, &len);
            
            if(s > 0) // 接收成功
            {
               buffer[s] = 0 ; //  ?  ? ? ? ? 
               uint16_t cli_port = ntohs(peer.sin_port);
               std::string cli_ip = inet_ntoa(peer.sin_addr); // 四字节整数ip 转为 string 类型 ；
               snprintf(key, sizeof(key), "%s-%u", cli_ip.c_str(), cli_port); // 为什么是 %u ？ ？ ？ 
               logMessage(NORMAL, "key: %s", key);

                auto it = _users.find(key);
                if(it == _users.end()) //说明查无此 ip 和 端口号 
                {
                    logMessage(NORMAL, "add new user : %s", key);
                    _users.insert({key,peer});
                }
            }


            // 向目标地址发送数据
            for(auto& iter : _users)
            {
                std::string sendMessage = key ;
                sendMessage += "# ";
                sendMessage += buffer;
                logMessage(NORMAL, "push message to %s", iter.first.c_str());
                sendto(_sock, sendMessage.c_str(), sendMessage.size(), 0, (sockaddr*)&(iter.second), sizeof(iter.second));
            }

        }

    }

    ~UdpServer()
    {
        if(_sock > 0 )
        {
            close(_sock) ; // ? ? ? ? ? ! ! ! ! 套接字用close函数关闭…… 
        }
    }



};